home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d3
/
e40ds3.arc
/
API.DOC
next >
Wrap
Text File
|
1989-03-10
|
24KB
|
555 lines
┌────────────────────────────────────┐
│E! APPLICATION PROGRAMMING INTERFACE│
│ │
│ PROGRAMMER'S GUIDE │
└────────────────────────────────────┘
A . INTRODUCTION
****************
The E! application programming interface allows you to write
programs that directly use E! functions or modify E! variables.
Since E! is an "in-memory-only" editor, it was a real concern to
provide the user with such an interface without using much memory
space. Moreover, it was important to find a way to program new
functions or E! "add-in" without requiring the programmer to learn
a new language such as the Brief macro language. Then I decided to
allow the programmer to write such programs with its own and usual
language whatever it could be (Pascal, C, etc..).
To achieve this goal I wrote a built-in interrupt handler thru
which the user may call E! functions, modify E! variables and
flags, access specific values FROM WITHIN an external program
executing while E! is present in memory. That is, from a program
loaded from the E! command line. This program will typically be
loaded using the "@" prefix so that it executes as a "blind"
command and that the DOS screen has not to be displayed.
With the E! API you can now write a program, say myaddin.exe,
that will be called from the E! command line (@myaddin) and that
can execute a E! command such as moving the cursor, marking and
manipulating blocks or modifying flags or variables.
This program may be a full-featured MENU that executes
functions without having to remember the required keystroke or a
program that performs a special job on the current text flow. You
can do almost anything you want using the E! API.
This approach has many advantages. First, it is not memory
consuming since the memory space used by the program is released
when the program finishes. Then you can use any language to write
an API program. Nothing new to learn. You just have to use a
language that can issue software interrupts and load the cpu
registers with the appropriate values. Another advantage is that
the size of the E!.EXE file remains almost unchanged after adding
the API.
The main difference with previous E! versions is the way E!
manages memory space when it calls a child process. This makes no
difference for the user.
B. THE E! API INTERRUPT
***********************
When E! is first loaded it traps interrupt C0h and redirects
it to an internal interrupt handler. This handler analyzes any
request addressed to it thru INT C0h and performs any action
requested. It then returns to the calling program.
Interrupt C0h is normally an unused interrupt vector. If there
is any conflict with existing hardware or software you may change
this interrupt number adding the following line in your active
PROFILE
INTERRUPT n
where n is the interrupt number (decimal) you want to use
instead of C0h.
┌─────────────────────────────────────────────────────────────────┐
│WARNING: │
│ │
│ IF YOU ALREADY COMPILED API PROGRAMS THAT USE INTERRUPT C0h │
│ OR ANY OTHER VALUE, THESE PROGRAMS WILL FAIL TO RUN WITH THIS │
│ NEW INTERRUPT NUMBER (i.e. P!.EXE) UNLESS YOU PATCH THEM. │
│ ANOTHER WAY TO HAVE THEM WORKING IN ANY CASE IS TO TEST THE │
│ E!PRESENT ENVIRONMENT VARIABLE (SEE BELOW). │
└─────────────────────────────────────────────────────────────────┘
Please, use this feature only in case of very particular
problems or needs.
Be aware that calling INT C0h when E! is not present in memory
will likely cause a system crash. To detect E! presence from your
API program you only have to test the E!PRESENT environment
variable which must yield 192 if E! uses the default interrupt
vector or any other value if you changed it. Only E! child
processes can see this variable. So this is a secure way to make
sure INT C0 has been installed. If E! is not present (or no more
present) this environment variable does not exist (unless you
create it). Only the E! child processes are able to see this
environment variable.
┌─────────────┐
│E!PRESENT=192│
└─────────────┘
The value of the EPRESENT environment variable is changed
dynamically whenever a new PROFILE containing a new INTERRUPT command
is loaded. So, if your API program tests this value it will execute
safely.
E! API INTERRUPT SERVICES
*************************
You may call the E! API interrupt to perform 7 kinds of tasks.
The task E! API will execute depends on the value you put in the AH
register when you call INT C0h. If AH is not set to a right value an
error code (FFh) is returned in AL.
1/ Calling a E! function - AH = 0
_________________________________
Calling INT C0h with AH set to 0 will execute the E! function
which code is loaded in BX. This code will be the same function code
described in the E! documentation for macros. See also the API.PAS
unit for this description.
MOV AH, 0
MOV BX, 5
INT C0h
will clear the current line from the cursor to the end of the
line.
So you can activate up to 108 basic E! functions.
Passing a function code > 32 or < 256 will be interpreted as a
normal character entry. Though it is not an efficient way of
writing a string to E!. You may want to use the Editbuffer to do
this.
Function code 27 (Escape) will be ignored and no error will be
returned.
The return code of the function is always returned in AL. This
value will be identical to the error codes described in the E!
documentation or 0 or 99 if the operation succeeded. See E!.DOC.
2/ Requesting internal addresses - AH = 1 to 7
______________________________________________
The E! API allows you to access and modify internal E!
variables. Actually the E! API will return the address of variables
blocks which structure is described below for each call from AH = 1
to AH = 7. The block address is always returned in the ES:BX
registers pair. There is no return code and AL is undefined on
exit.
AH = 1
******
On return ES:BX contains the address of the E! EditBuffer.
When you are editing a line in E! the actual text is not modified
until you leave the line (or the file) or execute a E! function.
This is why you can retrieve the previous content of the line when
you hit F9. Any modification made to the EditBuffer is stored to
the actual text when the cursor leaves the current line or when a
function is executed that needs to have the EditBuffer stored.
The E! Editbuffer is a 255 characters string. This is a Pascal
string. So the first byte contains the length of the string and the
string actually begins with the second byte. Space is reserved for
255 characters + 1 length byte.
The return code of the function is always returned in AL. This
value will be identical to the error codes described in the E!
documentation. See E!.DOC.
Modifying the EditBuffer will result in no action on the
screen (see AH = 9). This will not modify the actual text unless
you leave the current line, call a E! function or call the special
"store edit line" service with AH = 12. Be aware that certain
functions acting only the current line (hence on the editbuffer
only) will not store the editbuffer to the actual text.
Do not forget to update the EditBuffer length if you make
changes to the EditBuffer string without using Pascal strings
functions or procedures.
The reverse function (GetEditline) which stores the actual line
to the EditBuffer is always done automatically. So don't care.
AH = 2
******
On return ES:BX contains the address of the following block:
AddOnLast 1 byte Key down insert newline on last line flag
AlarmFlag 1 byte Error beep flag
AsciiMode 1 byte Control characters entry flag
AutoBackFlag 1 byte Backspace behaviour flag
AutoSaveFlag 1 byte Autosave flag
AutoScrollFlag 1 byte Autoscroll flag
AutoTabFlag 1 byte Autotab flag
BakFlag 1 byte .BAK files generation flag
BlanksFlag 1 byte Strip trailing spaces when saving flag
CompFlag 1 byte Compression mode flag
Ega_Vga_OK 1 byte 43 lines mode flag
Flag35 1 byte 35 lines mode flag - EGA_VGA_OK must be on
LogFlag 1 byte Log file flag
PauseMode 1 byte Pause on return from DOS flag
ShiftFlag 1 byte Accelerated cursor flag
Warning 1 byte Warning before saving flag
Enter_Classic 1 byte Split line using ENTER flag
RefreshFlag 1 byte Display authorization
There is only two possible values for each of these flags: 1
if the flag is TRUE and 0 if it is FALSE.
These flags correspond to the equivalent commands described in
the E! documentation.
Changing Ega_Vga_Ok and Flag35 will not set the corresponding
display mode. These are only "authorization" flags. You have to use
Ctrl G (function code 7) to activate this modes.
AH = 3
******
On return ES:BX points to the following structure:
Text_Attr 1 byte Edited text attribute
BlockAttr 1 byte Marked block attribute
CommandLineAttr 1 byte Command line attribute
LoStatusLineAttr 1 byte Status line 1 attribute
HiStatusLineAttr 1 byte Status line 2 attribute
MessageAttr 1 byte Messages attribute
HelpAttr 1 byte Help line attribute
CursorAttr 1 byte Virtual cursor attribute
Please note the following:
Changing the value of Text_Attr will NOT change the color of
the edited text unless you call the ResetMask service described
below (AH = 11). This applies to Text_Attr only.
AH = 4
******
On return ES:BX points to the following structure:
ShiftKeyCount 2 bytes Delay value for secondary help lines
AutoSaveLimit 2 bytes Keystrokes # for autosave
ScrollAmountGlb 2 bytes Left / Right scroll amount
DrawModel 2 bytes Drawing style
LeftMargin 2 bytes Left margin
ParMargin 2 bytes New paragraph margin
RightMargin 2 bytes Right margin
AH = 5
******
On return ES:BX points to the following structure:
HelpLine1 81 bytes 4 Pascal strings
to
HelpLine4 81 bytes "
ErrorMessage1 38 bytes 43 Pascal strings
(43 bytes for the french version)
to
ErrorMessage43 43 bytes "
Normally you will not need to access these message strings.
This service is only here for special needs.
AH = 6
******
On return ES:BX points to the "text flow" representing the
current text beeing edited. This pointer is actually the address of
an array of pointers. Each of these pointers points to a line of
text, that is, to a Pascal string representing a line of the text.
Array indexes are actual line numbers. So, the first element of
this array will point to the first line in the current text and so
on...
ES:BX ─────────> Ptr1 (4 bytes) ────────────> Line #1
Ptr2 (4 bytes) ────────────> Line #2
Ptr3 (4 bytes) ────────────> Line #3
Ptr4 (4 bytes) ────────────> Line #4
Ptr5 (4 bytes) ────────────> Line #5
.....
This array can be indexed up to the value returned in CX after
call #8. See AH = 8.
This call is made to READ the text lines NOT TO CHANGE them.
There is no extra space allocated for each string and any change to
the length of the string without reallocating the memory used by it
will likely result in a system crash when your program returns to E!.
To make changes to the text, access the lines with a E!
cursor positionning function or with function call number 14
(change active line). The EditBuffer will be loaded with the
requested line. Modify the EditBuffer and then store the new line
to the text using the "Store Edit Line " call.
E! is a complex machinery. Please respect these rules to keep
your memory and your files safe.
AH = 7
******
On return ES:BX points to a Pascal string representing the
full name of the current file beeing edited.
3/ Requesting screen status - AH = 8
____________________________________
On return the cpu registers are loaded with some specific
values that are of great interest for the E! API programmer:
CX contains the total number of lines in the current text
DX contains the current line number (from 1 to CX)
AH contains the cursor position (from 1 to 255)
AL contains the value of the first displayed column
BH contains the amount of lines displayed on the screen
(25, 35, 43 or 50)
BL contains the number of opened windows
There is no return code for this function.
4/ Requesting special services - AH = 9 to 13
_____________________________________________
AH = 9
******
This call will cause E! to display the current editbuffer.
Modifying the editbuffer does not modify the corresponding line on
the screen. If you need to do so, you have to call this function. Be
aware that this function DOES NOT store the EditBuffer to the actual
text. See AH = 12.
AH = 10
*******
This call will cause E! to rebuild the whole screen.
AH = 11
*******
This call will reset the text mask using the new value of
Text_Attr. The text mask is a structure used by E! to display the
text when a window is refreshed.
AH = 12
*******
This function will cause E! to store the content of the
EditBuffer to the actual text. PLEASE DO NOT try to do this yourself
using the value of the text flow pointer. The E! heap manager would
be fooled and an error would probably occur.
AH = 13
*******
This function sets the current text "change flag" to TRUE.
Please use it if you have made any change to the current text.
┌────────────────────────────────────────────┐
│There is no return code for these functions.│
└────────────────────────────────────────────┘
5/ Changing the active line - AH = 14
_____________________________________
AH = 14
*******
If the value passed in BX is a valid line number, this line
becomes the active line and also the first displayed line in the
active window. Likewise, the value passed in AL indicates the new
cursor position on the new line and also the new first displayed
column. This will avoid consistency problems beetween display and
cursor position. If either BX or AL contains 0 on entry, no action
is taken regarding the corresponding parameter. The other one is
processed normally. Otherwise AL will contain FFh on exit or 0 if
the operation succeeded. The Editbuffer is loaded with the content
of the new line. Its previous content is automatically stored to
the line that was active when this call was made.
This is the call you have to use if you want to directly
modify the current text.
6/ Requesting E! version - AH = 15
__________________________________
On return AH will contain the "major" digit of the E! version
and AL will contain the minor digit. i.e. for version 4.0 AH will
return 4 and AL will return 0.
7/ Registering a E! command - AH = 16
_____________________________________
As stated below it is not possible to execute E! commands
(commands entered on the E! command line) from an external program.
The main reason for that is that the command processor code is not
and CANNOT be reentrant.
However you may need to request a command execution. The E!
API offers a limited way of executing a command from an external
program. Your API program may "register" a command using call
number 16. When the API program EXITS, the command will be
executed. You may register the command anywhere in your API
program. You may register only one command. Though if you register
several commands, only the last one will be executed.
To register a command you have to pass the address of a Pascal
string representing the command exactly as if you entered it on the
E! command line, in the ES:BX registers pair. Then call INT C0h with
AH set to 16. That's all.
Please note that this call allows you to easily chain API
programs. The registered command may be a call to another API program
and so on...
The P! program is an example of what can be achieved using this
call. This program allows you to choose a file from a pick list to
have it edited. The P! source file contains copyrighted material, so
it cannot be released. However it is easy to understand that once the
filename has been choosen from the pick list, it can be passed along
with the EDIT command using call number 16. When the API program
returns, the file will be loaded.
The REFRESH flag
****************
By default, E! will automatically refresh the screen if
necessary after each function call (AH = 0). If you find this
somewhat tedious or if you want to spare time, you may disable the
screen refresh process by setting the REFRESH flag to FALSE before
the function calls are made and resetting it to TRUE after these
calls. You MUST reset this flag to TRUE before your program
terminates. If you fail to do so, E! will do it for you if your
program has been loaded with the "@" prefix. The REFRESH flag is
accessed thru the call number 2. This is the last flag of the
structure.
C. THE HEAP MANAGEMENT
**********************
You may wonder how E! manage the memory to allow you to use
the full system memory when no external program is active and still
allow E! functions to execute when the same external program is
loaded on the top of E! even if these functions make an extensive
use of the heap. This is one of the E! programming secrets. However
the user has to control the memory amount left between E! and the
API program.
If your program only changes variables values or call E!
functions that do not make use of the heap, you may leave this
value unchanged (it defaults to 256 paragraphs) or even set it to
0. Though there is very few E! functions that do not make use of
the heap or that do not call a subroutine that uses the heap
itself. So it will be almost always necessary to preserve some
space for the E! heap before calling the API program .
This is done using a command in the E! main profile:
HEAP n
n representing the number of PARAGRAPHS (16 bytes) you want to
preserve. The value you will use will highly depend on what your
program actually does and what E! functions it calls. The E! MEMORY
command will always show you the amount of free memory available
for your program to run. Substract from this value the memory space
needed by your program plus a security and you will have
approximately the value to pass to the HEAP command in your
profile.
It is allowed to set the HEAP parameter to 0 if you don't need
the E! API.
This space is reserved whatever the command you used to make
the dos shell, that is, even if you did not use the "@" prefix.
If there not enough memory space reserved for the E! functions
your program calls, E! will behave exactly the same as if these
commands have been launched from the keyboard. So you will get an
error message and so on... If your program fails because it lacks
memory space, try a greater value for the HEAP command parameter.
D. AN API EXAMPLE
*****************
The API.PAS file provided with the API documentation is an
example of an implementation of a turbo pascal UNIT interfacing the
E! API. Reading this commented code will help you understand how the
API works.
E. CONCLUSION
*************
If you want to write your own menu or complex macros or whatever
function you will find useful you have now a simple to use interface
to E!. It is highly recommended that programs written for the E! API
be called with the "@" prefix from the E! command line.
It is up to the API programmer to make sure that the E! screen
is not destroyed during program execution. E! does not refresh the
screen when it returns from a child process called with the "@"
prefix.
You may wonder why there is no provision in the E! API to
execute a E! command exactly as if you typed it on the E! command
line. The answer is quite obvious : a E! command can also be a DOS
command. Imagine your API program is executing and you ask E! to
execute another child process...
Have fun!
Patrick Philippot 12/16/1988